package com.beta.cat.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.RandomAccessFile;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 日志收集工具类
 *
 * @author kevin_zhang
 * @date 2018/6/29
 */
public class LogCollectionUtil {
    private static Logger logger = LoggerFactory.getLogger(LogCollectionUtil.class);

    private static long RESPONSE_TIME_FAST = 300;
    private static long RESPONSE_TIME_NORMAL = 2000;

    private static String getFunctionExecuteLevel(long optDuration) {
        if (optDuration <= RESPONSE_TIME_FAST) {
            return "RESPONSE_FAST";
        } else if (optDuration > RESPONSE_TIME_FAST && optDuration <= RESPONSE_TIME_NORMAL) {
            return "RESPONSE_NORMAL";
        } else {
            return "RESPONSE_BAD";
        }
    }

    /**
     * 收集接口API日志
     *
     * @param request
     * @param resultObj
     * @param beginTime
     * @param endTime
     */
    public static Map logCollection(HttpServletRequest request, Object resultObj, long beginTime, long endTime, boolean isPrintResult) {
        Map logMap = new HashMap();
        try {
            String url = request.getRequestURL().toString();
            String[] urlArr = url.split("/");
            String apiName = "";
            if (null != urlArr && urlArr.length > 0) {
                apiName = urlArr[urlArr.length - 1];
            }
            logMap.put("q_action", "stat_" + apiName);
            logMap.put("q_action_detail", url);
            logMap.put("q_ip", RequestParamUtil.getClientIp(request));
            logMap.put("q_opt_time", beginTime);

            Map maps = request.getParameterMap();
            if (!maps.isEmpty()) {
                logMap.put("q_req_param", maps);
            } else {
                String queryStr = request.getQueryString();
                if (null != queryStr && queryStr.length() > 0) {
                    queryStr = URLDecoder.decode(request.getQueryString(), "UTF-8");
                    logMap.put("q_req_param", queryStr);
                }
            }
            if (!logMap.containsKey("q_req_param")) {
                logMap.put("q_req_param", maps);
            }

            dealLogMap(logMap, resultObj, endTime, isPrintResult);
        } catch (Exception ex) {
            ex.printStackTrace();
            logger.error("collection log error" + ex.getMessage());
        }
        return logMap;
    }

    /**
     * 收集RMI API日志
     *
     * @param functionName
     * @param paramMap
     * @param resultObj
     * @param beginTime
     * @param endTime
     * @param isPrintResult
     * @return
     */
    public static Map rpcLogCollection(String functionName, LinkedHashMap paramMap, Object resultObj, long beginTime, long endTime, boolean isPrintResult) {
        Map logMap = new HashMap();
        try {
            logMap.put("q_action", "stat_" + functionName.substring(functionName.lastIndexOf(".") + 1));
            logMap.put("q_action_detail", functionName);
            logMap.put("q_opt_time", beginTime);
            if (!paramMap.isEmpty()) {
                logMap.put("q_req_param", paramMap);
            }

            dealLogMap(logMap, resultObj, endTime, isPrintResult);
        } catch (Exception ex) {
            logger.error("collection log error" + ex.getMessage(), ex);
        }
        return logMap;
    }

    public static List<String> readLastLines(String fileName, String charset, int numLines) {
        return readLastLines(Paths.get(fileName), charset, numLines);
    }

    public static List<String> readLastLines(Path filePath, String charset, int numLines) {
        charset = StringUtils.defaultIfBlank(charset, "UTF-8");
        RandomAccessFile file = null;
        try {
            long fileSize = Files.size(filePath);

            // 使用RandomAccessFile类读取文件
            file = new RandomAccessFile(filePath.toFile(), "r");

            // 用于存储最后几行的队列
            Deque<String> lastLines = new ArrayDeque<>(numLines);

            String line;
            int numLinesRead = 0;
            long pos = fileSize - 1;

            // 从文件末尾开始逐行读取数据
            while (pos >= 0 && numLinesRead < numLines) {
                file.seek(pos);
                char c = (char) file.readByte();
                // 如果是换行符，则读取一行数据，并将记录添加到队列中
                if (c == '\n') {
                    line = file.readLine();
                    if (line != null) {
                        lastLines.offerFirst(new String(line.getBytes("ISO-8859-1"), charset));
                        numLinesRead++;
                    }
                }
                pos--;
            }
            return lastLines.stream().collect(Collectors.toList());
        } catch (Exception e) {
        } finally {
            // 关闭文件
            try {
                file.close();
            } catch (Exception e) {
            }
        }
        return null;
    }

    private static void dealLogMap(Map logMap, Object resultObj, long endTime, boolean isPrintResult) {
        long optTime = Long.parseLong(logMap.get("q_opt_time").toString());
        long optDuration = endTime - optTime;
        logMap.put("q_opt_speed", getFunctionExecuteLevel(optDuration));
        logMap.put("q_opt_duration", optDuration);

        if (isPrintResult) {
            logMap.put("q_opt_result", resultObj);
        }

        logger.info(JSON.toJSONString(logMap));
    }
}
